/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#ifndef __BLENDER_SKELETON_LOAD_IMPL_H__
#define __BLENDER_SKELETON_LOAD_IMPL_H__

#include "GPrerequisites.h"

#include "OgreMatrix4.h"
#include "OgreSkeleton.h"
#include "OgreBone.h"

#include "blender.h"
#include "bMain.h"
#include "bBlenderFile.h"

namespace GNgine
{
	/** Internal class that used to store blender bone data
        @remarks
			This class shouldn't used by user.
    */
	class BlenderBone
	{
	public:
		typedef std::vector<BlenderBone*> BoneList;

		BlenderBone(const Ogre::String name,short handle,Blender::Bone *bone=0,Blender::Bone* prevBone=0)
			: _name(name),_handle(handle), bBone(bone),bPrevBone(prevBone),
			parentMat(Ogre::Matrix4::IDENTITY),boneMat(Ogre::Matrix4::IDENTITY),
			poseMat(Ogre::Matrix4::IDENTITY),poseInvert(Ogre::Matrix4::IDENTITY),
			parent(0),old_poseloc(0,0,0),old_poseskl(1,1,1),old_poserot(1, 0, 0, 0)
		{
			_id=_list.size();
			_list.push_back(this);
		}

		inline short getHandle()
		{
			return _handle;
		}

		inline Ogre::String getName()
		{
			return _name;
		}
		

		inline static int getBoneCount()
		{
			return _list.size();
		}

		inline static BlenderBone* get(int id)
		{
			if(id>=0&&id<_list.size()){
				return _list[id];
			}
			return 0;
		}
		
	private:
		static BoneList _list;
		int _id;
		Ogre::String _name;
		
	public:
		Blender::Bone *bBone;
		Blender::Bone *bPrevBone;//prev bone
		BlenderBone* parent;

		Ogre::Bone* bone;//Ogre bone	
		Ogre::Matrix4 parentMat;//inverse matrix
		Ogre::Matrix4 boneMat;
		Ogre::Matrix4 poseMat;
		Ogre::Matrix4 poseInvert;
		short _handle;

		// cache
		Ogre::Vector3 old_poseloc;
		Ogre::Vector3 old_poseskl;
		Ogre::Quaternion old_poserot;
		
	};


	/** Internal class that used to load blender skeleton data into Ogre mesh.
        @remarks
			This class shouldn't used by user,just an implementation of blender skeleton loader.
    */
	class BlenderSkeletonLoadImpl
	{
	public:
		typedef std::map<Ogre::String,BlenderBone*> BoneList;
		BlenderSkeletonLoadImpl(bParse::bBlenderFile* blenderFile,Blender::Object *object,  Ogre::Skeleton *skeleton);
		void load();
	private:
		void buildBoneTree(Blender::Bone *current, Blender::Bone *prev,BlenderBone* parent);
		void actionToAnimation(Blender::bPose *pose, Blender::bAction *action);
		Blender::bActionChannel *findActionChannel(const char *name, Blender::bAction *action);
		void setPoseMatrices(Blender::bPose *pose, Blender::bAction *action,const Ogre::Real& time);
		void buildPoseTreeKeyFrame(Ogre::Animation *anim, Blender::Bone *cur, BlenderBone *parent, const Ogre::Real& time);

	private:
		bParse::bBlenderFile* _bFile;
		Blender::Object *_bObject;
		Ogre::Skeleton* _skeleton;

		BoneList _bones;

		Ogre::Matrix4 _transform;
		Blender::bArmature *_bArmature;

	};
}

#endif
